﻿#define _CRT_SECURE_NO_WARNINGS
#include"Snake.h"

//光标定位函数
void SetPos(short x,short y)
{
	HANDLE output = NULL;
	output = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	SetConsoleCursorPosition(output,pos);
}

void CreateMap()
{
	//最后一页打印地图   创建地图
	int i = 0;
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}

//欢迎界面打印函数
void Welcome()
{
	//其次定位光标的位置   进行欢迎界面信息的打印    
	SetPos(40, 12);
	wprintf(L"欢迎来到贪吃蛇小游戏！\n");
	SetPos(42, 16);
	system("pause");
	system("cls");
	SetPos(36, 10);
	wprintf(L"★ 请用← ↑ → ↓进行操控哦 ★\n");
	SetPos(35, 12);
	wprintf(L"加速食物分值更高 减速食物分值较低\n");
	SetPos(36, 14);
	wprintf(L" *_* 不可以撞墙和咬到自己哦 *_*\n");
	SetPos(40, 16);
	wprintf(L"F3进行加速  F4进行减速\n");
	SetPos(38, 18);
	wprintf(L"!!!努力获得更高的分数吧!!!\n");
	SetPos(42, 21);
	system("pause");
	system("cls");
}

//创建蛇身（*出错*）
void CreateSnake(pSnake psnake)
{
	pSnakeNode snakeNode = NULL;
	for (int i = 0; i < 5; i++)
	{
		snakeNode = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (snakeNode == NULL)
		{
			perror("malloc");
			return;
		}
		snakeNode->next = NULL;   //(24,5)坐标节点的下一个
		snakeNode->x = POS_X+2*i;   
		snakeNode->y = POS_Y;	  //把后续的坐标都表示

	//进行头插连接并且打印
		if (psnake->pSnakeHead == NULL)
		{
			//本身为空
			psnake->pSnakeHead =snakeNode;
		}
		else
		{
			snakeNode->next = psnake->pSnakeHead;
			psnake->pSnakeHead = snakeNode;
		}
	}
	//连接完成  进行打印
	snakeNode = psnake->pSnakeHead;
	while (snakeNode)
	{
		SetPos(snakeNode->x, snakeNode->y);
		wprintf(L"%lc", BODY);
		snakeNode = snakeNode->next;
	}
	//设置蛇的具体属性(展示分数和帮助信息)
	psnake->Dir = RIGHT;
	psnake->Score = 0;
	psnake->FoodScore = 10;
	psnake->SleepTime = 200;
	psnake->Status = OK;
}

//创建食物(横坐标2的倍数  x在2-54的范围内  y在1-25  食物若不为2的倍数需要重新生成)     *出错*
void CreateFood(pSnake psnake)
{
	int x = 0;
	int y = 0;
again:	
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x%2!=0);
	//开辟  x y生成  x,y不能与蛇身冲突
	pSnakeNode cur = psnake->pSnakeHead;
	while (cur)
	{
		if (cur->x == x && cur->y == y)
		{
			goto again;
		}
		cur = cur->next;
	}
	//排除问题  创建食物节点
	pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pFood == NULL)
	{
		perror("malloc");
		return;
	}
	pFood->x = x;
	pFood->y = y;
	pFood->next = NULL;
	SetPos(x,y);
	wprintf(L"%lc", FOOD);
	//让食物节点信息给贪吃蛇里面的食物  面向对象  更好维护
	psnake->pFood = pFood;
}

//游戏初始化
void GameInit(pSnake psnake)
{
	//首先要设置窗口大小并对光标进行清理
	system("mode con cols=100 lines=30");    //设置窗口大小  mode con
	system("title 贪吃蛇");
	HANDLE output = NULL;   //创建HANDLE 类型变量
	output = GetStdHandle(STD_OUTPUT_HANDLE);    //获取句柄（输出框)
	CONSOLE_CURSOR_INFO Cursor;   //设置一个光标结构体变量
	GetConsoleCursorInfo(output, &Cursor);    //获得句柄中的光标信息
	Cursor.bVisible = false;
	SetConsoleCursorInfo(output, &Cursor);    //设置句柄中的光标信息

	Welcome();

	CreateMap();

	CreateSnake(psnake);

	CreateFood(psnake);
	
}

//帮助信息
void PrintHelp()
{

	SetPos(62, 14);
	wprintf(L"* 请用← ↑ → ↓进行操控 *\n");
	SetPos(65, 16);
	wprintf(L"F3进行加速  F4进行减速\n");
	SetPos(64, 18);
	wprintf(L"ESC退出游戏  空格暂停游戏\n");

	SetPos(63, 22);
	wprintf(L"版权所属   天♂夏 @ 辞游\n");
}

//按空格的暂停函数
void Pause()
{
	while (1)
	{
		Sleep(200);
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}

//下一节点是食物
//void EatFood(pSnakeNode snakenode,pSnake psnake)
//{
//	//头插
//	snakenode->next = psnake->pSnakeHead;
//	psnake->pSnakeHead = snakenode;
//	pSnakeNode cur = NULL;
//	cur = psnake->pSnakeHead;
//	while (cur)
//	{
//		SetPos(cur->x, cur->y);
//		wprintf(L"%lc", BODY);
//		cur = cur->next;
//	}
//}

//void NoFood(pSnakeNode snakenode, pSnake psnake)
//{
//	snakenode->next = psnake->pSnakeHead;
//	psnake->pSnakeHead = snakenode;
//	pSnakeNode cur = NULL;
//	cur = psnake->pSnakeHead;
//	while (cur->next->next != NULL)
//	{
//		SetPos(cur->x, cur->y);
//		wprintf(L"%lc", BODY);
//		cur=cur->next;
//	}
//
//	pSnakeNode del = cur->next;
//	SetPos(del->x, del->y);
//	printf("  ");
//	cur->next = NULL;
//	free(del);
//	del = NULL;
//}

//判断下一个节点是否是食物
int NextIsFood(pSnakeNode pnextnode,pSnake psnake)
{
	return (pnextnode->x == psnake->pFood->x && pnextnode->y == psnake->pFood->y);
}

//是食物  吃掉实物
void EatFood(pSnakeNode pnextnode, pSnake psnake)
{
	//头插(和食物一样  把食物信息赋给  释放下一个节点)
	psnake->pFood->next = psnake->pSnakeHead;
	psnake->pSnakeHead = psnake->pFood;

	free(pnextnode);
	pnextnode = NULL;

	//遍历打印蛇
	pSnakeNode cur = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (cur == NULL)
	{
		perror("malloc");
		return;
	}
	cur = psnake->pSnakeHead;
	while (cur)
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
	psnake->Score += psnake->FoodScore;
	CreateFood(psnake);
}

//不是食物
void NoFood(pSnakeNode pnextnode, pSnake psnake)
{
	pnextnode->next = psnake->pSnakeHead;
	psnake->pSnakeHead = pnextnode;

	pSnakeNode cur = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (cur == NULL)
	{
		perror("malloc");
		return;
	}
	cur = psnake->pSnakeHead;
	while (cur->next->next != NULL)   //循环条件应该就是打印到倒数第二个
	{
		SetPos(cur->x, cur->y);
		wprintf(L"%lc", BODY);
		cur = cur->next;
	}
 //定位到最后cur->next(最后一个节点)结点的位置   然后对应位置输出两个空格
	SetPos(cur->next->x, cur->next->y);
	printf("  ");

	free(cur->next);    //最后一节点释放
	cur->next = NULL;   //倒数第二个节点next置空
}

//如果撞墙
void IsKillByWall(pSnake psnake)
{
	if (psnake->pSnakeHead->x == 0 || psnake->pSnakeHead->x == 56 || psnake->pSnakeHead->y == 0 || psnake->pSnakeHead->y == 26)
	{
		psnake->Status = KillByWall;
	}
}

//如果自杀
void IsKillBySelf(pSnake psnake)
{
	pSnakeNode cur = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (cur == NULL)
	{
		return;
	}
	cur = psnake->pSnakeHead->next;

	while (cur)
	{
		if (psnake->pSnakeHead->x == cur->x && psnake->pSnakeHead->y == cur->y)
		{
			psnake->Status = KillBySelf;
			break;
		}
		cur = cur->next;
	}
}

//蛇的移动走一步函数
void SnakeMove(pSnake psnake)
{
	pSnakeNode pnextnode = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (pnextnode == NULL)
	{
		perror("malloc");
		return;
	}
	//走一步要检测往哪个方向运行   然后对应修改坐标位置   (*注意*  此处修改的是下一个节点的位置   出错)
	switch (psnake->Dir)
	{
	case UP:
		pnextnode->x=psnake->pSnakeHead->x;
		pnextnode->y = psnake->pSnakeHead->y - 1;
		break;
	case DOWN:
		pnextnode->x = psnake->pSnakeHead->x;
		pnextnode->y = psnake->pSnakeHead->y + 1;
		break;
	case LEFT:
		pnextnode->x = psnake->pSnakeHead->x - 2;
		pnextnode->y = psnake->pSnakeHead->y;
		break;
	case RIGHT:
		pnextnode->x = psnake->pSnakeHead->x + 2;
		pnextnode->y = psnake->pSnakeHead->y;
		break;
	}

	//判断下一个节点是否是食物
	if (NextIsFood(pnextnode, psnake))
	{
		EatFood(pnextnode,psnake);   //是食物  吃掉食物
	}
	else
	{
		NoFood(pnextnode, psnake);   //不是食物
	}

	//走一步判断一次是否撞墙或者撞自己
	IsKillByWall(psnake);
	IsKillBySelf(psnake);
}

void GameRun(pSnake psnake)
{
	PrintHelp();

	//检测按键情况（每一次都要进行检测）
	do
	{
		SetPos(64, 8);
		printf("总 分 数：%d\n", psnake->Score);
		SetPos(64, 10);
		printf("此食物分数： %2d\n", psnake->FoodScore);
		if (KEY_PRESS(VK_UP) && psnake->Dir != DOWN)
		{
			psnake->Dir = UP;
		}
		else if (KEY_PRESS(VK_DOWN) && psnake->Dir != UP)
		{
			psnake->Dir = DOWN;
		}
		else if (KEY_PRESS(VK_RIGHT) && psnake->Dir != LEFT)
		{
			psnake->Dir = RIGHT;
		}
		else if (KEY_PRESS(VK_LEFT) && psnake->Dir != RIGHT)
		{
			psnake->Dir = LEFT;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			psnake->Status = EndNormal;
		}
		else if (KEY_PRESS(VK_F3))
		{
			if (psnake->SleepTime > 100)
			{
				psnake->SleepTime -= 20;
				psnake->FoodScore += 2;
			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			if (psnake->FoodScore > 2)
			{
				psnake->SleepTime += 20;
				psnake->FoodScore -= 2;
			}
		}
		SnakeMove(psnake);   //走一步  休眠一次
		Sleep(psnake->SleepTime);

	} while (psnake->Status == OK);

	//pSnakeNode snakenode = (pSnakeNode)malloc(sizeof(SnakeNode));
	//if (snakenode == NULL)
	//{
	//	perror("malloc");
	//	return;
	//}
	//snakenode->next = NULL;
	//snakenode->x = psnake->pFood->x;
	//snakenode->y = psnake->pFood->y;
	//
	////下一节点是食物
	//if (psnake->pSnakeHead->x == snakenode->x && psnake->pSnakeHead->y == snakenode->y)
	//{
	//	EatFood(snakenode, psnake);
	//}
	//下一节点不是食物
	//else
	//{
	//	NoFood(snakenode,psnake);
	//}
}


//善后工作
void GameEnd(pSnake psnake)
{
	SetPos(10, 12);    //定位 进行输出
	//对游戏状态检测
	switch (psnake->Status)
	{
		case EndNormal:
			printf("你退出了游戏！\n");
			break;
		case KillBySelf:
			wprintf(L"%ls", L"||-_-| 咬到自己了哦，下次要小心呀，游戏结束！\n");
			break;
		case KillByWall:
			wprintf(L"%ls", L"撞墙了 |-_-|| 下次可要加油哦，游戏结束！\n");
			break;
	}
	//对节点挨个释放(*注 意*)
	pSnakeNode cur = psnake->pSnakeHead;
	while (cur)
	{
		pSnakeNode del = cur;
		cur = cur->next;
		free(del);
	}
}